package com.imis.module.api.bus;

import com.baomidou.mybatisplus.annotation.DbType;
import com.google.common.base.Joiner;
import com.imis.base.constant.CommonConstant;
import com.imis.base.constant.DataBaseConstant;
import com.imis.base.constant.DictCodeConstant;
import com.imis.base.constant.enums.ArgumentResponseEnum;
import com.imis.base.constant.permissions.PermissionsValueConstant;
import com.imis.base.globle.response.CommonResponse;
import com.imis.base.util.ConvertUtils;
import com.imis.base.util.PackageClassUtils;
import com.imis.module.api.model.ro.DictItemsByCodeQueryDTO;
import com.imis.module.api.model.ro.DictItemsQueryDTO;
import com.imis.module.api.model.vo.ClassParameter;
import com.imis.module.base.BaseBus;
import com.imis.module.system.model.ro.QueryDictTreeDTO;
import com.imis.module.system.model.vo.DictVO;
import com.imis.module.system.model.vo.DropDownBoxTreeVO;
import com.imis.module.system.service.ISysDictService;
import com.imis.module.system.service.ISysMenuService;
import com.imis.module.system.service.ISysOrganizationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * DropDownBoxBus<br>
 * 公共 业务处理类
 * </p>
 *
 * @author XinLau
 * @version 1.0
 * @since 2020年05月29日 17:37
 */
@Slf4j
@Service
public class DropDownBoxBus extends BaseBus {

    /**
     * 字典项 服务类
     */
    private ISysDictService serviceBySysDictService;

    @Autowired
    public void setServiceBySysDictService(ISysDictService serviceBySysDictService) {
        this.serviceBySysDictService = serviceBySysDictService;
    }

    /**
     * 组织机构 服务类
     */
    private ISysOrganizationService sysOrganizationService;

    @Autowired
    public void setSysOrganizationService(ISysOrganizationService sysOrganizationService) {
        this.sysOrganizationService = sysOrganizationService;
    }

    /**
     * 功能菜单表 服务类
     */
    private ISysMenuService serviceBySysMenuService;

    @Autowired
    public void setServiceBySysMenuService(ISysMenuService serviceBySysMenuService) {
        this.serviceBySysMenuService = serviceBySysMenuService;
    }

    /**
     * 验证参数合法性
     *
     * @param table     - 表名
     * @param textField - 字段名
     * @param codeField - 字段值
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/6/12 11:24
     */
    private void verifyParameter(final String table, final String textField, final String codeField) {
        // 1.参数数组
        String[] fieldArray = {textField, codeField};
        // 2.数据表、字段合法性校验
        boolean verifyTable = this.serviceBySysDictService.verifyTable(table, fieldArray);
        ArgumentResponseEnum.DICT_QUERY_ERR_FIELD_NON.assertIsTrue(verifyTable);
    }

    /**
     * 根据定时任务Class类名获取定时任务执行方法的参数信息
     *
     * @param classParameterArrayList - 定时任务
     * @param aClass                  - 定时任务Class类
     * @return List<ClassParameter>  -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/7/18 8:35
     */
    private void getClassParameterByClassName(List<ClassParameter> classParameterArrayList, final Class aClass) {
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            if (!"executeInternal".equals(method.getName()) && !"doQuartzJob".equals(method.getName())) {
                // 方法的参数参数类型列表
                Type[] parameterTypeList = method.getGenericParameterTypes();
                // 方法的参数参数名列表
                Parameter[] parameterNameList = method.getParameters();
                if (parameterTypeList.length == parameterNameList.length) {
                    for (int i = 0; i < parameterTypeList.length; i++) {
                        String name = parameterNameList[i].getName();
                        String typeName = parameterTypeList[i].getTypeName();
                        classParameterArrayList.add(new ClassParameter(name, typeName));
                    }
                }
            }
        }
    }

    /**
     * 根据字典编码（code）获取下拉
     *
     * @param dictCode - 字典编码（code）
     * @return CommonResponse<List < DictVO>>
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<DictVO>> queryDictItemsByDictCode(final String dictCode) {
        ArgumentResponseEnum.DICT_QUERY_ERR_CODE_NULL.assertNotEmpty(dictCode);
        List<DictVO> dictList = this.serviceBySysDictService.queryDictItemsByDictCode(dictCode);
        return new CommonResponse<>(dictList);
    }

    /**
     * 通过查询指定表（table）的 字段（text、code）进行条件SQL语句（filterSql）检索查询数据成为字典结果
     *
     * @param sysDictItemsQuery 指定表、字段的下拉查询对象
     * @return CommonResponse<List < DictVO>>
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/5/12 9:55
     */
    public CommonResponse<List<DictVO>> queryTableDictItemsByParameter(final DictItemsQueryDTO sysDictItemsQuery) {
        // 条件SQL语句
        String filterSql = sysDictItemsQuery.getFilterSql();
        // 1.验证参数合法性
        this.verifyParameter(sysDictItemsQuery.getTable(), sysDictItemsQuery.getTextField(), sysDictItemsQuery.getCodeField());
        // 2.验证SQL条件合法性
        ArgumentResponseEnum.DICT_QUERY_ERR_SQL_ILLEGAL.assertIsFalse(ConvertUtils.containsSqlInjection(filterSql));
        // 3.查询字典信息
        List<DictVO> dictList = this.serviceBySysDictService.queryTableDictItemsByParameter(sysDictItemsQuery);
        return new CommonResponse<>(dictList);
    }

    /**
     * 通过查询指定表（table）的 字段（text、code）进行指定内容（code）的检索查询数据成为字典结果
     *
     * @param sysDictItemsByCodeQuery 指定表、字段的指定内容下拉查询对象
     * @return CommonResponse<List < DictVO>>
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/5/12 9:55
     */
    public CommonResponse<List<DictVO>> queryTableDictItemsByCode(final DictItemsByCodeQueryDTO sysDictItemsByCodeQuery) {
        // 1.验证参数合法性
        this.verifyParameter(sysDictItemsByCodeQuery.getTable(), sysDictItemsByCodeQuery.getTextField(), sysDictItemsByCodeQuery.getCodeField());
        // 2.查询字典信息
        List<DictVO> dictList = this.serviceBySysDictService.queryTableDictItemsByCode(sysDictItemsByCodeQuery);
        return new CommonResponse<>(dictList);
    }

    /**
     * 根据组织机构名称获取下拉
     *
     * @param organizationName - 组织机构名称
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<DropDownBoxTreeVO>> queryOrganizationTreeByOrganizationName(final String organizationName) {
        // 1.查询组织机构下拉
        List<DropDownBoxTreeVO> dropDownBoxTreeList = this.sysOrganizationService.queryOrganizationTreeByOrganizationName(organizationName);
        return new CommonResponse<>(dropDownBoxTreeList);
    }

    /**
     * 根据功能菜单名称获取下拉
     *
     * @param menuName - 功能菜单名称
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<DropDownBoxTreeVO>> queryMenuTreeByMenuName(final String menuName) {
        // 1.查询功能菜单下拉
        List<DropDownBoxTreeVO> dropDownBoxTreeList = this.serviceBySysMenuService.queryMenuTreeByMenuName(menuName);
        return new CommonResponse<>(dropDownBoxTreeList);
    }

    /**
     * 条件查询字典树
     *
     * @param queryDictTree - 字典树查询对象
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<DropDownBoxTreeVO>> queryDictTreeListByParameter(final QueryDictTreeDTO queryDictTree) {
        // 1.查询字典树下拉
        List<DropDownBoxTreeVO> dropDownBoxTreeList = this.serviceBySysDictService.queryDictTreeListByParameter(queryDictTree);
        return new CommonResponse<>(dropDownBoxTreeList);
    }

    /**
     * 获取定时任务的Class类名
     *
     * @return Result
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<String>> queryQuartzJobClassName() {
        // 1.查询定时任务下拉
        List<String> classNameList = PackageClassUtils.getClazzName(CommonConstant.QUARTZ_CLASS_NAME, false);
        classNameList.remove("com.imis.module.quartz.QuartzJobInitialization");
        log.debug(Joiner.on(",").join(classNameList));
        return new CommonResponse<>(classNameList);
    }

    /**
     * 获取定时任务Class类的参数信息
     *
     * @param className - 定时任务Class类名
     * @return CommonResponse<List < ClassParameter>>
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<ClassParameter>> queryQuartzJobParameterName(final String className) {
        List<ClassParameter> classParameterArrayList = new ArrayList<>();
        // 1.判断是否属于定时任务
        if (className.startsWith(CommonConstant.QUARTZ_CLASS_NAME)) {
            try {
                Class aClass = Class.forName(className);
                this.getClassParameterByClassName(classParameterArrayList, aClass);
            } catch (ClassNotFoundException e) {
                log.debug(e.getMessage(), e);
            }
        }
        return new CommonResponse<>(classParameterArrayList);
    }

    /**
     * 获取请求权限常量类内的常量
     *
     * @param modeName - 模块名关键字
     * @return CommonResponse<List < String>>
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<String>> queryPermissionsValueConstantField(final String modeName) {
        Field[] fields = PermissionsValueConstant.class.getDeclaredFields();
        List<String> fieldArrayList = new ArrayList<>(fields.length);
        for (Field field : fields) {
            try {
                String permissionsValue = field.get(field.getName()).toString();
                if (ConvertUtils.isNotEmpty(modeName)) {
                    if (permissionsValue.contains(modeName)) {
                        fieldArrayList.add(permissionsValue);
                    }
                } else {
                    fieldArrayList.add(permissionsValue);
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
            }
        }
        return new CommonResponse<>(fieldArrayList);
    }

    /**
     * 获取DictCode常量
     *
     * @return CommonResponse<List < String>>
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<String>> queryDictCodeConstantField() {
        Field[] fields = DictCodeConstant.class.getDeclaredFields();
        List<String> fieldArrayList = new ArrayList<>(fields.length);
        for (Field field : fields) {
            try {
                fieldArrayList.add(field.get(field.getName()).toString());
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
            }
        }
        return new CommonResponse<>(fieldArrayList);
    }

    /**
     * 获取数据库类型常量
     *
     * @return CommonResponse<List < DictVO>>
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<DictVO>> queryDataBaseType() {
        List<DictVO> dictList = new ArrayList<>();
        try {
            for (DbType dataBaseType : DbType.values()) {
                DictVO dict = new DictVO(dataBaseType.getDb(), dataBaseType.getDesc());
                dictList.add(dict);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return new CommonResponse<>(dictList);
    }

    /**
     * 获取多数据源方法名常量
     *
     * @return CommonResponse<List < String>>
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/30 12:01
     */
    public CommonResponse<List<String>> queryMultipleDataSourcesMethodName() {
        Field[] fields = DataBaseConstant.class.getDeclaredFields();
        List<String> fieldArrayList = new ArrayList<>();
        for (Field field : fields) {
            String name = field.getName();
            if (name.contains("DATA_SOURCE_")) {
                try {
                    String dataSourceName = String.valueOf(field.get(name));
                    fieldArrayList.add(dataSourceName);
                } catch (IllegalAccessException e) {
                    log.error(e.getMessage());
                }
            }
        }
        return new CommonResponse<>(fieldArrayList);
    }

}
